In [24]:
%run ../trajectory.ipynb
import csv
This document is for comparing different configurations of liquid propellant. Before a design optimization can occur, we must specify certain propellant characteristics, as determined by our selection and the outputs of CEArun. However, it is not immediately obvious from just thermodynamic properties how various propellant configurations will effect the rocket's performance as a whole. Hence, this.
In order to compare propellant configurations, we make the ceterus paribus assumption that all other aspects of the LV4 rocket are held constant. The canonical outputs of our Multi-disciplinary Design Optimization are used to dictate the total mass of propellants, total mass flow rates, and exit pressure. The same trajectory simulation that is used in the MDO is used here to numerically integrate the results of launching a rocket with a given propellant configuration.
We must explicitly choose the following pieces of information:
The following pieces of information are given by CEArun:
This script requires only a .csv file with one row for each propellant configuration and one column for each parameter.
The relevant outputs of each trajectory simulation are saved as a text file.
In [2]:
# canonical lv4 design variables
m_prop_can = 123.35069377654865
mdot_can = 2.6244828455178943
p_e_can = 42.974369360377864
# canonical propellant configuration, for reference
# combustion gas properties ke, Re, T_ch, determined from CEArun
# with chamber pressure=350 psi, fuel temp=419.15 K,
# lox temp=90 K, OF=1.3 for fuel = 64.8% IPA (2propanol) / 35.2% H20
rho_ipa = 849.28 # kg/m^3 Density of 64.8% IPA / 35.2% H20
OF = 1.3 # O/F ratio, this is somewhat arbitrary but CEA says its good.
p_ch = 350 # chamber pressure, PSI
T_ch = 3097.82 # chamber temperature, K
ke = 1.1251 # specific heat ratio, propellant (aka gammas)
M = 23.196 # molar mass
Re = spec_gas(M) # specific gas constant, propellant
First of all, I'm sorry about the hacky use of global variables. They don't cause any problems, but they are unsightly.
test_run takes a given propellant configuration, runs a trajectory simulation, and returns the simulation object.
print_results takes a simulation object and an index number, and saves all the relevant information from the trajectory to a text file in ./propellants/ named by the index.
load_csv takes a string that names a .csv file, and returns an isomorphic multidimensional array.
run_batch takes no explicit arguments and the name of the .csv file as an implicit parameter, and then runs and saves a trajectory simulation for each propellant configuration.
The last code block of this document simply calls run_batch(). The end-user need only concern themself with setting up the .csv file correctly.
In [3]:
def test_run(ipa, OF_param, p_ch, T_ch, ke, M, comment): # OF implicitly invoked, don't worry
global OF, rho_ipa # I SAID I'M SORRY!!
rho_ipa = ipa
OF = OF_param
Re = spec_gas(M)
sim = trajectory(m_prop_can, mdot_can, dia, p_e_can,
p_ch=p_ch, T_ch=T_ch, ke=ke, Re=Re)
sim.comment = comment
sim.OF = OF_param
sim.ipa = rho_ipa
sim.M = M
return sim
In [4]:
# this creates a list of relevant strings from trajectory
def print_results(sim, index):
text_base = [] # list of lines of strings
np.set_printoptions(precision=3) # this line may be deprecated, i copy-pasted most of this section
text_base.append('INPUTS')
text_base.append('\nComment: ' + sim.comment)
text_base.append('\nFuel density = %5.3f kg/m^3' % sim.ipa)
text_base.append('\nO/F ratio = %5.3f ' % sim.OF)
text_base.append('\nchamber pressure = {:.3f} kPa'.format(sim.p_ch/1000))
text_base.append('\nChamber temperature = {:.3f} K'.format(sim.T_ch))
text_base.append('\nSpecific heat ratio = %5.3f' % sim.ke)
text_base.append('\nMolar mass = %5.3f' % sim.M)
text_base.append('\nSpecific gas constant = %5.3f J/K' % sim.Re)
text_base.append('\n')
text_base.append('\nDESIGN PARAMETERS')
text_base.append('\n-----------------------------')
text_base.append('\ndesign total propellant mass = {:.3f} kg'.format(m_prop_can))
text_base.append('\ndesign mass flow rate = {:.3f} kg/s'.format(mdot_can))
text_base.append('\ndesign nozzle exit pressure = {:.3f} kPa'.format(p_e_can))
text_base.append('\n')
text_base.append("\nENGINE SYSTEM DETAILS")
text_base.append("\n-----------------------------")
text_base.append('\ndesign Throat pressure = {:.3f} kPa'.format(sim.p_t/1000))
text_base.append('\ndesign Throat temperature = {:.3f} K'.format(sim.T_t))
text_base.append('\ndesign exit velocity = {:.3f} m/s'.format(sim.Ve))
text_base.append('\ndesign thrust (ground level) = {:.3f} kN'.format(sim.F[0]/1000))
text_base.append('\ndesign thrust (vacuum) = {:.2f} kN'.format(sim.F[sim.F_index]/1000))
text_base.append('\ndesign expansion ratio = {:.3f}'.format(sim.ex))
text_base.append('\ndesign Exit area = {:.3f} in.^2'.format(sim.A_e/0.0254**2))
text_base.append('\ndesign throat area = {:.3f} in.^2'.format(sim.A_t/0.0254**2))
text_base.append('\ndesign isp = {:.3f} s'.format(sim.Ve/g_n))
text_base.append('\ndesign total impulse = {:.3f} kN*s'.format(
sim.t[sim.F_index]*(sim.F[sim.F_index]/1000 + sim.F[0]/1000)/2))
text_base.append('\ndesign dV = {:.3f} km/s'.format(sim.dV1))
text_base.append('\nmission time at burnout = {:.3f} s'.format(sim.t[sim.F_index]))
text_base.append('\n\nPlumbing Details\n------------------')
# Mass flow for each propllent
mdot_o, mdot_f = proportion(mdot_can)
text_base.append("\nOx flow: . . . . . . . . . . %7.3f kg/s" % mdot_o)
text_base.append("\nFuel flow: %7.3f kg/s" % mdot_f)
# Propellent Mass for each propllent
mprop_o, mprop_f = proportion(m_prop_can)
text_base.append("\nOx mass: . . . . . . . . . . . %5.3f kg" % mprop_o)
text_base.append("\nFuel mass: %5.3f kg" % mprop_f)
# dimensions of each tank
text_base.append("\nTank outer diameters: . . . . . . . %7.3f m" % (2*sim.r))
text_base.append("\nOx tank length + ullage: %7.3f m" % sim.l_o)
text_base.append("\nFuel tank length + ullage: %7.3f m" % sim.l_f)
# Tank thickness for each tank (mm)
thickness_o = tank_thickness(Al, sim.r)
thickness_f = tank_thickness(CF, sim.r)
text_base.append("\nOx tank thickness: %5.3f mm" % (thickness_o*1000))
text_base.append("\nFuel tank thickness: %5.3f mm" % (thickness_f*1000))
# Mass of each tank
m_tank_o = tank_mass(sim.l_o, Al, sim.r)
m_tank_f = tank_mass(sim.l_f, CF, sim.r)
text_base.append("\nOx tank mass: . . . . . . . . %5.3f kg" % m_tank_o)
text_base.append("\nFuel tank mass: %5.3f kg" % m_tank_f)
text_base.append('\n')
text_base.append('\nRELEVANT CONSTRAINTS')
text_base.append('\n-----------------------------')
text_base.append('\naltitude at apogee (c.f. > {}) = {:.3f} km'.format(
cons_alt/1000, sim.alt[-1]/1000))
text_base.append("\nmax acceleration (c.f. < {}) = {:.3f} gs".format(
cons_accel, sim.max_g_force))
text_base.append('\nTWR at lift off (c.f. > {}) = {:.3f}'.format(cons_TWR, sim.TWR))
text_base.append('\nspeed when leaving launch rail (c.f. > {}) = {:.3f} m/s'.format(cons_ls,sim.launch_speed))
with open('propellants/'+str(index)+'_info.txt', 'w') as info:
for line in text_base:
info.write(line)
In [5]:
def load_csv(file_name):
designs = []
with open(file_name) as text:
csv_reader = csv.reader(text, delimiter=',')
counter = 0
for line in csv_reader:
if counter != 0:
designs.append(line)
counter += 1
return designs
In [6]:
def run_batch():
designs = load_csv('propellants/propellants.csv')
for i, des in enumerate(designs):
run = test_run(float(des[0]), float(des[1]), float(des[2]),
float(des[3]), float(des[4]), float(des[5]), des[6])
print_results(run, i)
In [7]:
run_batch()